本篇将介绍输入事件在View树中的分发机制。
事件产生
输入事件是通过InputManager的InputDispatcher分派给WMS的,在创建ViewRootImpl时会建立和WMS的关联,实际上是两个InputChannel,这两个InputChannel是一个socketpair分别负责读和写事件信息。这样事件就可以通过ViewRootImpl分发给view树。
1 | final class ViewPostImeInputStage extends InputStage { |
产生的事件最终是交给DecorView也就是view树的根节点进行分发的,对于Touch事件,它是通过dispatchTouchEvent进行分发的,DecorView实际上是一个ViewGroup,这里我们看它的dispatchTouchEvent方法
1 |
|
在ViewGroup的dispatchTouchEvent中,主要做了以下事情:
- 判断是否有允许事件拦截,如果允许拦截则通过onInterceptTouchEvent拦截事件,并将处理的结果保存。
- 如果未进行拦截处理,就需要为ACTION_DOWN寻找一个TargetView,实际上就是将事件分发给子view进行处理,如果子view对其进行处理即在dispatchTransformedTouchEvent返回true,则它就是TargetView,后续ACTION_MOVE,ACTION_UP事件会分发给它。
- 如果没有找到TargetView,则交由ViewGroup自身进行事件处理。
1 | public boolean dispatchTouchEvent(MotionEvent event) { |
子View对于事件先通过onTouch进行处理,如果onTouch消费了此次事件,则直接返回true表示子view处理了本次事件,否则通过onTouchEvent进行处理,同样的,返回true表示处理了本次事件,View的dispatchTouchEvent类似。
1 | private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel, |
在dispatchTransformedTouchEvent中当child为null时,即没有子view或者子view都不对事件进行处理,则通过ViewGroup自身的dispatchTouchEvent进行消化处理,否则是交给子view进行处理,处理的结果handled作为事件是否被消费的依据,如果handled为true表示事件被消费了,这样事件就不需要在view树中进行传递了。
view树的事件传递机制比较简答,读者可以分别阅读view和viewGroup的dispatchTouchEvent部分相关的代码即可。